package com.zyl.Ecs.realtime.web.websocket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zyl.Ecs.common.domain.data.bean.DataBean;
import com.zyl.Ecs.common.domain.data.vo.DataVO;
import com.zyl.Ecs.common.domain.device.ext.SensorEdl;
import com.zyl.Ecs.common.domain.device.ext.SensorExt;
import com.zyl.Ecs.common.domain.device.vo.PositionVO;
import com.zyl.Ecs.common.utils.CUtil;
import com.zyl.Ecs.realtime.client.DeviceClient;
import com.zyl.Ecs.realtime.config.AbstractBaseWebSocket;
import com.zyl.Ecs.realtime.config.ApplicationContextRegister;
import com.zyl.Ecs.realtime.service.RealTimeService;
import com.zyl.Ecs.realtime.util.TableUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Component;

import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @version v1.0
 * @ProjectName: Ecs
 * @Package: com.zyl.Ecs.realtime.web.websocket
 * @ClassName: RealTimeWebSocket
 * @Description TODO (实时数据websocket)
 * @Author 翟玉龙
 * @Date 2024/12/6-16:59
 */
@Component
@ServerEndpoint(value = "/status",subprotocols = {"protocol"})
public class RealTimeWebSocket extends AbstractBaseWebSocket {

    private final DeviceClient client;
    private final RealTimeService realTimeService;

    /* WebSocket传输间隔 */
    private static final long WEBSOCKET_TIME_INTERVAL = 5000L;

    /* 计数 */
    private static int number = 0;

    /* 初始化加载client */
    {
        this.client = ApplicationContextRegister.getApplicationContext().getBean(DeviceClient.class);
        this.realTimeService = ApplicationContextRegister.getApplicationContext().getBean(RealTimeService.class);
    }

    public RealTimeWebSocket() {

    }

    /**
     * 实时数据处理
     *
     * @return {@link List }<{@link DataVO }>
     */
    private List<DataVO> initList() {
        /* 获取点位扩展 */
        CUtil.logInfo("     获取点位扩展中.....");
        List<PositionVO> positionVOS= client.listPositions().getData();
        /* 获取传感器扩展 */
        CUtil.logInfo("     获取传感器扩展中.....");
        List<SensorExt> sensorExtList = client.listSensorsMore().getData();
        /* 获取动态表名 */
        CUtil.logInfo("     构建动态表名中.....");
        List<String> tableNames = positionVOS.stream()
                .flatMap(positionVO -> positionVO.getSensorIds().stream()
                        .map(TableUtil::tableName))
                .collect(Collectors.toList());

        /* 获取实时数据 （每个传感器表中最新一条数据）列表 */
        CUtil.logInfo("     获取实时数据中.....");
        List<DataBean> dataBeans = realTimeService.getRealTimeData(tableNames);

        /* 使用 Map 来存储传感器 ID 和其对应的 DataBean */
        Map<Integer, DataBean> dataBeanMap = dataBeans.stream()
                .collect(Collectors.toMap(DataBean::getSensorId, dataBean -> dataBean));

        /* 封装实时数据 */
        CUtil.logInfo("     封装实时数据中.....");
        List<DataVO> dataVOS = new ArrayList<>();
        for (PositionVO positionVO : positionVOS) {
            dataVOS.add(
                    DataVO.builder()
                            .id(positionVO.getId())
                            .positionName(positionVO.getName())
                            .sensorData(sensorTypeInit(positionVO, sensorExtList, dataBeanMap))
                            .build()
            );
        }
        CUtil.logInfo("     封装实时数据完成,正在返回中.....");
        return dataVOS;
    }


    /**
     * 传感器类型初始化
     *
     * @param positionVO 点位vo
     * @param sensorExtList 传感器扩展列表
     * @param dataBeanMap 数据bean映射
     * @return {@link List }<{@link String }>
     */
    private List<SensorEdl> sensorTypeInit(PositionVO positionVO, List<SensorExt> sensorExtList,Map<Integer, DataBean> dataBeanMap) {
        /* 构建返回对象 */
        List<SensorEdl> result = new ArrayList<>();
        /* 筛选出所需传感器类型 */
        List<SensorExt> collect = sensorExtList.stream()
                .filter(sensorExt -> positionVO.getSensorIds().contains(sensorExt.getId()))
                .collect(Collectors.toList());

        /* 封装传感器缩略类型 */
        for (SensorExt sensorExt : collect) {
            DataBean dataBean = dataBeanMap.get(sensorExt.getId());
            SensorEdl edl = SensorEdl.toEdl(sensorExt, dataBean);
            result.add(edl);
        }
        return result;
    }


    /**
     * 新客户端连接
     * @param session 会话对象
     */
    @OnOpen
    public void opOpen(Session session) {
        this.session = session;
        webSocketSet.add(this);
        CUtil.logInfo(
                String.format(
                        "[websocket] 有新的连接请求展示屏数据，当前总数：%s",
                        webSocketSet.size()
                )
        );

        // 开始发送实时数据
        CUtil.logInfo("开始发送实时数据.......");
        startSendTask();
    }


    /**
     * 向客户端发送消息
     *
     */
    public void startSendTask() {
        // 读取刷新间隔
        Long interval = WEBSOCKET_TIME_INTERVAL;
        // 启动定时任务，每秒传输1条
        CUtil.logInfo("启动定时任务，每" + WEBSOCKET_TIME_INTERVAL / 1000 + "秒传输1条");
        timer.schedule(
                new SocketTimeTask(this.session.getBasicRemote()),
                0,
                Optional.of(interval).orElse(1000L));
    }

    @AllArgsConstructor
    class SocketTimeTask extends TimerTask {

        private final RemoteEndpoint.Basic remote;

        @Override
        public void run() {
            if (!run) {
                cancel();
            }

            try {
                /* 记录开始时间 */
                long startTime = System.currentTimeMillis();
                List<DataVO> list = initList();
                CUtil.logInfo(
                        String.format(
                                "[websocket] 向展示屏发送数据，当前数据：%s",
                                list
                        )
                );
                /* 记录结束时间 */
                long endTime = System.currentTimeMillis();
                CUtil.logInfo("发送数据耗时：" + (endTime - startTime) + "ms");
                CUtil.logInfo(String.format(
                        "当前完成第%d次数据传输",
                        ++number
                ));
                /* 换行分割（这里换两行） */
                System.out.println("\n");

                if (!list.isEmpty()) {
                    // 使用Jackson库构建JSON字符串
                    ObjectMapper objectMapper = new ObjectMapper();
                    String jsonString = objectMapper.writeValueAsString(list);
                    remote.sendText(jsonString);
                } else {
                    remote.sendText("[]");
                }
            } catch (Exception e) {
                try {
                    remote.sendText("服务器繁忙，请稍后重试！");
                } catch (IOException ioException) {
                    CUtil.logError("Socket通信出现错误：" + e);
                }
            }
        }
    }

}
